package com.wsm.common.shiro;

import com.wsm.common.config.ApplicationContextRegister;
import com.wsm.common.service.RedisService;
import com.wsm.common.utils.ShiroUtils;
import com.wsm.system.domain.UserDO;
import com.wsm.system.mapper.UserDao;
import com.wsm.system.service.MenuService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.wsm.common.enums.Constant.LIMIT_LOG;
import static com.wsm.common.enums.Constant.LOG_UNSUCCESS_NUM;


public class UserRealm extends AuthorizingRealm {

	/**
	 * 验证权限
	 * @param arg0
	 * @return
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		Long userId = ShiroUtils.getUserId();
		MenuService menuService = ApplicationContextRegister.getBean(MenuService.class);
		Set<String> perms = menuService.listPerms(userId);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setStringPermissions(perms);
		return info;
	}

	/**
	 * 登录验证
	 * @param token
	 * @return
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
		String username = (String) token.getPrincipal();
		Map<String, Object> map = new HashMap<>(16);
		map.put("username", username);
		RedisService redisService = ApplicationContextRegister.getBean(RedisService.class);
		String limitKey = LIMIT_LOG + username;
		if (redisService.hasKey(limitKey)) {
			throw new ExcessiveAttemptsException();
		}
		String password = new String((char[]) token.getCredentials());
		UserDao userMapper = ApplicationContextRegister.getBean(UserDao.class);
		// 查询用户信息
		UserDO user = userMapper.list(map).get(0);
		// 账号不存在
		if (user == null) {
			throw new UnknownAccountException();
		}
		// 密码错误
		String key = LOG_UNSUCCESS_NUM + username;
		if (!password.equals(user.getPassword())) {
			//redis增加登录次数时间限制
			if (redisService.hasKey(key)) {
				if (redisService.increment(key) >= 5) {
					redisService.set(limitKey, 0, 5, TimeUnit.MINUTES);
					redisService.del(key);
					//限制登录
					throw new ExcessiveAttemptsException();
				}
			} else {
				redisService.set(key, 0, 5, TimeUnit.MINUTES);
			}
			//密码错误
			throw new IncorrectCredentialsException();
		} else {
			if (redisService.hasKey(limitKey)) {
				redisService.del(limitKey);
			}
			if (redisService.hasKey(key)) {
				redisService.del(key);
			}
		}
		// 账号锁定
		if (user.getStatus() == 0) {
			throw new LockedAccountException();
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
		return info;
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(Object principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

}
